package ace.cmp.application.core.support.listener;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

/**
 * @author caspar 监听服务是否启动成功, 并输出注册的bean
 */
@Slf4j
@Builder
@AllArgsConstructor
public class PrintBeansApplicationReadyEventListener
    implements ApplicationListener<ApplicationReadyEvent> {

  private final ApplicationContext applicationContext;

  /**
   * 是否打印bean name
   */
  private final Boolean printBeanNamesEnable;

  /**
   * 是否打印mvc mapping handler
   */
  private final Boolean printMappingHandlerEnable;

  /**
   * 应用名称
   */
  private final String applicationName;

  @Override
  public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {

    ConfigurableApplicationContext ctx = applicationReadyEvent.getApplicationContext();
    StringBuilder allBeanNameStr = new StringBuilder(500);
    allBeanNameStr.append(System.lineSeparator());
    allBeanNameStr.append("----------------- spring beans start ------------------------");

    allBeanNameStr.append(System.lineSeparator());
    String[] beanNames = ctx.getBeanDefinitionNames();
    allBeanNameStr.append("bean 总数：" + beanNames.length);
    if (this.printBeanNamesEnable) {
      allBeanNameStr.append(System.lineSeparator());
      Arrays.sort(beanNames);
      for (String beanName : beanNames) {
        String beanClassName = ctx.getBean(beanName).getClass().getName();
        allBeanNameStr.append("name:" + beanName + System.lineSeparator());
        allBeanNameStr.append("class:" + beanClassName + System.lineSeparator());
      }
      allBeanNameStr.append(System.lineSeparator());
    }
    if (this.printMappingHandlerEnable) {
      RequestMappingHandlerMapping mapping =
          applicationContext.getBean(
              "requestMappingHandlerMapping", RequestMappingHandlerMapping.class);
      // 获取url与类和方法的对应信息
      Map<RequestMappingInfo, HandlerMethod> map = mapping.getHandlerMethods();
      for (RequestMappingInfo info : map.keySet()) {
        if (info.getPatternsCondition() == null || info.getPatternsCondition().isEmpty()) {
          continue;
        }
        // 获取url的Set集合，一个方法可能对应多个url
        Set<String> patterns = info.getPatternsCondition().getPatterns();
        for (String url : patterns) {
          // 把结果存入静态变量中程序运行一次次方法之后就不用再次请求次方法
          allBeanNameStr.append(url);
          allBeanNameStr.append(System.lineSeparator());
        }
      }
      allBeanNameStr.append(System.lineSeparator());
    }
    allBeanNameStr.append(System.lineSeparator());
    allBeanNameStr.append("----------------- spring beans end --------------------------");
    allBeanNameStr.append(System.lineSeparator());
    allBeanNameStr.append(
        String.format(
            "###############[微服务启动成功]###[%s]###[%s]##############",
            LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")),
            this.applicationName));
    allBeanNameStr.append(System.lineSeparator());
    log.info(allBeanNameStr.toString());
  }
}
